#include "ncspropedit.h"
#include "ncsprop_utils.h"
#include <QApplication>
#include <QMouseEvent>

#include <QLabel>
#include <QKeyEvent>
#include <QToolButton>
#include <QFontDialog>
#include <QColorDialog>
#include <QAbstractItemView>

//--------------------------------------------------------------------------------------------------NpBoolEdit
NpBoolEdit::NpBoolEdit(NcsProp* prop,QWidget* parent) 
    : NcsPropEdit(prop, parent)
    , m_checkBox(new QCheckBox(this))
    , m_textVisible(true)
{
    QHBoxLayout *hbox = new QHBoxLayout;
    if (QApplication::layoutDirection() == Qt::LeftToRight)
        hbox->setContentsMargins(4, 0, 0, 0);
    else
        hbox->setContentsMargins(0, 0, 4, 0);
    hbox->addWidget(m_checkBox);
    setLayout(hbox);
    m_checkBox->setCheckState( prop->value().toBool() ? Qt::Checked : Qt::Unchecked); 
    updateTextVisible();
    this->setFocusProxy(m_checkBox);
    connect(m_checkBox, &QCheckBox::toggled, [this](bool is_toggled) 
        { 
            m_prop->propMgr()->setValue(m_prop, m_checkBox->isChecked());
            this->updateTextVisible(); 
        });
}

void NpBoolEdit::loadPropValue(const NcsProp* prop) 
{
    bool is_true = prop->value().toBool();
    m_checkBox->setCheckState( is_true ? Qt::Checked : Qt::Unchecked); 
    updateTextVisible();
}

void NpBoolEdit::mousePressEvent(QMouseEvent *event)
{
    if (event->buttons() == Qt::LeftButton) {
        m_checkBox->click();
        event->accept();
    }
    else {
        QWidget::mousePressEvent(event);
    }
}

void NpBoolEdit::updateTextVisible()
{
    if (m_textVisible)
        m_checkBox->setText(m_checkBox->isChecked() ? tr("True") : tr("False"));
    else
        m_checkBox->setText(QString());
}
void NpBoolEdit::setTextVisible(bool textVisible)
{
    if (m_textVisible == textVisible)
        return;

    m_textVisible = textVisible;
    updateTextVisible();

}

//-------------------------------------------------------------------------------------------------- NcsEnumEdit {

NpComboBox::NpComboBox(NcsProp* prop, QWidget* parent )
	: QComboBox(parent)
    , m_prop(prop)
{
    this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
    this->view()->setTextElideMode(Qt::ElideRight);
    this->setCurrentIndex(dynamic_cast<NcsEnumProp*>(m_prop)->currentIndex());
    connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetValue(int)));
}

void NpComboBox::slotSetValue(int index) 
{
    // by default, int value will be used as property's value. 
    int int_val = this->itemData(index, Qt::UserRole).toInt(); 
    m_prop->setValue(int_val); 
}

void NpComboBox::setItemAndData(const QStringList& item_labels, QVariantList item_data ) 
{
    if (item_data.isEmpty() ) { 
        for (auto p : item_labels)
            item_data.append(p);
    }

    if (item_labels.size() != item_data.size() && item_labels.size() == 0)
        qFatal("Item labels and data are not match. "); 

    this->blockSignals(true);
    this->clear(); 
    this->addItems(item_labels); 
    for ( int i = 0; i<item_labels.size(); ++i)
        this->setItemData(i, item_data[i], Qt::UserRole); 
    this->blockSignals(false);

    this->setCurrentIndex(dynamic_cast<NcsEnumProp*>(m_prop)->currentIndex());
}

// NcsEnumEdit }

//----------------------------------------------------------------------------------------NcsStringEnumEdit {

void NcsStringEnumEdit::slotSetValue(int index) 
{
    // by default, string value will be used as property's value. 
    QString text = this->itemData(index, Qt::UserRole).toString(); 
    m_prop->propMgr()->setValue(m_prop, text);
}

// NcsStringEnumEdit }


//----------------------------------------------------------------------------------------NcsFontEdit {

NcsFontEdit::NcsFontEdit(NcsProp* prop, QWidget *parent) :
    NcsPropEdit(prop, parent),
    m_pixmapLabel(new QLabel),
    m_label(new QLabel),
    m_button(new QToolButton)
{
    m_font = prop->value().value<QFont>(); 
    QHBoxLayout *lt = new QHBoxLayout(this);
    utils::setupTreeViewEditorMargin(lt);
    lt->setSpacing(0);
    lt->addWidget(m_pixmapLabel);
    lt->addWidget(m_label);
    lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));

    m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
    m_button->setFixedWidth(20);
    setFocusProxy(m_button);
    setFocusPolicy(m_button->focusPolicy());
    m_button->setText(tr("..."));
    m_button->installEventFilter(this);
    connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked()));
    lt->addWidget(m_button);
    updateEditor(m_font);
}

void NcsFontEdit::updateProp(const QFont &f)
{
    if (m_font != f) {
        m_font = f;
        m_prop->propMgr()->setValue(m_prop, f);
    }
}

void NcsFontEdit::updateEditor(const QFont &f)
{
    m_pixmapLabel->setPixmap(utils::createPixmapFromFont(f));
    m_label->setText(utils::fontValueText(f));
}

void NcsFontEdit::buttonClicked()
{
    bool ok = false;
    QFont newFont = QFontDialog::getFont(&ok, m_font, this, tr("Select Font"));
    if (ok && newFont != m_font) {
        QFont f = m_font;
        // prevent mask for unchanged attributes, don't change other attributes (like kerning, etc...)
        if (m_font.family() != newFont.family())
            f.setFamily(newFont.family());
        if (m_font.pointSize() != newFont.pointSize())
            f.setPointSize(newFont.pointSize());
        if (m_font.bold() != newFont.bold())
            f.setBold(newFont.bold());
        if (m_font.italic() != newFont.italic())
            f.setItalic(newFont.italic());
        if (m_font.underline() != newFont.underline())
            f.setUnderline(newFont.underline());
        if (m_font.strikeOut() != newFont.strikeOut())
            f.setStrikeOut(newFont.strikeOut());
        updateProp(f);
        updateEditor(f);
    }
}

bool NcsFontEdit::eventFilter(QObject *obj, QEvent *ev)
{
    if (obj == m_button) {
        switch (ev->type()) {
        case QEvent::KeyPress:
        case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate
            switch (static_cast<const QKeyEvent*>(ev)->key()) {
            case Qt::Key_Escape:
            case Qt::Key_Enter:
            case Qt::Key_Return:
                ev->ignore();
                return true;
            default:
                break;
            }
        }
            break;
        default:
            break;
        }
    }
    return QWidget::eventFilter(obj, ev);
}
//----------------------------------------------------------------------------------------NcsFontEdit }

//----------------------------------------------------------------------------------------NcsColorEdit {

NcsColorEdit:: NcsColorEdit(NcsProp* prop, QWidget *parent) :
    NcsPropEdit(prop, parent),
    m_pixmapLabel(new QLabel),
    m_label(new QLabel),
    m_button(new QToolButton)
{
    QHBoxLayout *lt = new QHBoxLayout(this);
    m_color = prop->value().value<QColor>(); 
    utils::setupTreeViewEditorMargin(lt);
    lt->setSpacing(0);
    lt->addWidget(m_pixmapLabel);
    lt->addWidget(m_label);
    lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));

    m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
    m_button->setFixedWidth(20);
    setFocusProxy(m_button);
    setFocusPolicy(m_button->focusPolicy());
    m_button->setText(tr("..."));
    m_button->installEventFilter(this);
    connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked()));
    lt->addWidget(m_button);
    updateEditor(m_color);
}

void NcsColorEdit::updateProp(const QColor &c)
{
    if (m_color != c) {
        m_color = c;
        m_prop->propMgr()->setValue(m_prop, c);
    }
}

void NcsColorEdit::updateEditor(const QColor &c)
{
    m_pixmapLabel->setPixmap(utils::brushValuePixmap(QBrush(c)));
    m_label->setText(utils::colorValueText(c));
}


void NcsColorEdit::buttonClicked()
{
    const QColor newColor = QColorDialog::getColor(m_color, this, QString(), QColorDialog::ShowAlphaChannel);
    if (newColor.isValid() && newColor != m_color) {
        updateProp(newColor);
        updateEditor(newColor); 
    }
}

bool NcsColorEdit::eventFilter(QObject *obj, QEvent *ev)
{
    if (obj == m_button) {
        switch (ev->type()) {
        case QEvent::KeyPress:
        case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate
            switch (static_cast<const QKeyEvent*>(ev)->key()) {
            case Qt::Key_Escape:
            case Qt::Key_Enter:
            case Qt::Key_Return:
                ev->ignore();
                return true;
            default:
                break;
            }
        }
            break;
        default:
            break;
        }
    }
    return QWidget::eventFilter(obj, ev);
}

//----------------------------------------------------------------------------------------NcsColorEdit }


